fix(identity): self-heal the "two names" split + self-report (#351)#362
Merged
Conversation
…t self-report The recurring "display name ≠ actual name" bug: a Claude session's statusline shows one wire identity while the session operates on wire as another. Confirmed live — a dot session's statusline read daydream-gorge (its CLAUDE_CODE_SESSION_ID) while its MCP served merry-spindle, a key matching no live session. Box-wide it's systemic: 434 running wire procs, 115 serving an identity no live session uses. Root cause: the long-lived `wire mcp` server resolves + FREEZES its identity at launch; the statusline re-resolves live each render. When they diverge — the MCP booted before Claude wrote its session pidfile, so resolve_session_key() missed and the server minted a throwaway `mcp-proc-*` key, pinned it into WIRE_SESSION_ID, and served it for life — you get two permanent names. The prior dash detection (9c3b62a) couldn't see it: a fresh CLI's env is already live, so its env-vs-pidfile check never inspected the frozen MCP process. Fixes: - session.rs: before minting at MCP startup, RETRY the pidfile (walk the ancestor chain ONCE, re-read only the cached pids across a short backoff — no per-hop `ps` re-fork, avoiding the #353 Windows perf trap). Recovers the live identity instead of freezing a throwaway one. Stop pinning the minted key into WIRE_SESSION_ID (that slot is the operator-override / live channel; a minted value parked there masqueraded as an override and beat the live session on re-resolve — the root of the split). WIRE_HOME already pins the process + is inherited by children. - session.rs: redesign detect_identity_split to compare OPERATIONAL identity (the home this process serves) vs LIVE pidfile identity — so the frozen MCP itself detects the split, which the old env-vs-pidfile check structurally could not. Fixes a latent bug exposed by the redesign: handle_for_key sanitized the key before hashing, but homes are created from the raw key hash; sanitize_name truncates at 32 chars, so a 36-char session-id uuid resolved to the wrong home and the split silently returned None. (Caught by the in-situ gate, not units.) - mcp.rs: surface `identity_split` in wire_status + wire_whoami (null when healthy) so an agent self-detects drift at the session-start health check it already runs, instead of waiting for a human to run `wire dash`. - setup.rs: bake `env:{WIRE_SESSION_ID:"${CLAUDE_CODE_SESSION_ID}"}` into the canonical MCP entry `wire setup` writes, so the forward survives `--apply` (was a hand-edit the next apply overwrote). Inert on non-Claude hosts (the ${...} guard rejects an unexpanded value). Prevention for every new session. Existing frozen MCPs heal on next /mcp reconnect; the fix + self-report make that one-command recovery visible. 8 new tests; 643 lib tests green; fmt + clippy clean. In-situ: reproduced the split with real homes/pidfile — banner fires; silent when healthy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VxnZEjrcrYR3SAq8Crv8hg
…et-share, document self-report Gate-2 (fresh-eyes review of the built diff) found one blocker + three majors: - BLOCKER (perf): detect_identity_split was wired into wire_status/wire_whoami (the session-start hot path) but re-walked the parent chain — up to 16 untimed `ps` forks — on EVERY call, on a box with 434 wire procs. Cache the ancestor chain in a OnceLock (a process's parentage is immutable): the bounded walk happens once, every later identity check re-reads only the tiny pidfiles. - MAJOR (false positive): the RFC-008 §C "deliberate fleet-share" WIRE_HOME pin (several sessions intentionally sharing one identity) tripped the detector forever. Suppress when session_source is an explicit operator WIRE_HOME pin (env:WIRE_HOME / env:WIRE_HOME_FORCE) — wire's own minted/claude-* resolution, the real bug case, is never suppressed. - MAJOR (undocumented): the new identity_split field was present but no agent was told to check it. Added it to the wire_status + wire_whoami descriptions and to the "ON SESSION START" instructions block (surface it, /mcp reconnect, don't send/pair until resolved) — the wiring that makes the self-report actionable. - MAJOR (test): the regression guard didn't call handle_for_key. Added a hermetic test (tempdir WIRE_HOME) that drives handle_for_key directly and proves a raw 36-char uuid key resolves its home while the sanitized/truncated form misses — fails if handle_for_key ever re-adds sanitize_name. Plus a suppression test. In-situ (real homes + pidfile): fire path fires (operational=merry-spindle ≠ live=verdant-palm); fleet-share WIRE_HOME pin now suppressed (0 banner lines); healthy silent; cached walk still resolves the live session. 647 lib tests green; fmt + clippy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VxnZEjrcrYR3SAq8Crv8hg
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VxnZEjrcrYR3SAq8Crv8hg
Deploying wireup-landing with
|
| Latest commit: |
697f315
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://7b70e99a.wireup-landing.pages.dev |
| Branch Preview URL: | https://fix-two-names-identity-selfh.wireup-landing.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
A Claude session's statusline shows one wire identity while the session operates on wire as another. Confirmed live: a session whose
CLAUDE_CODE_SESSION_IDderiveddaydream-gorgewas sending/pairing asmerry-spindle, a key matching no live session. Systemic — 115 of 434 runningwireprocs served an identity no live session used.Root cause
The long-lived
wire mcpserver freezes its identity at launch; the statusline re-resolves live each render. When the MCP boots before Claude writes its session PID-file,resolve_session_key()misses → the server mints a throwawaymcp-proc-*key, pins it intoWIRE_SESSION_ID, and serves it for life. The priorwire dashdetection couldn't see it — a fresh CLI's env is already live, so it never inspected the frozen MCP process.Fix
psre-fork / fix(mcp): wire_send uses a cheap pidfile liveness check, not the full scan (#350) #353 Windows trap) → recovers the live identity.WIRE_SESSION_ID— that slot is the operator-override / live channel; a minted value there beat the live session on re-resolve (the root of the split).WIRE_HOMEalready pins the process + children.detect_identity_splitcompares served vs live-PID-file identity → the frozen MCP self-detects the drift the old env-vs-pidfile check structurally couldn't. Surfaced as anidentity_splitfield onwire_status/wire_whoami(+ documented in the MCP session-start instructions) so an agent self-reports and recommends/mcp reconnect. RFC-008 deliberate fleet-share (WIRE_HOMEpin) is exempt.wire setupbakesenv:{WIRE_SESSION_ID:"${CLAUDE_CODE_SESSION_ID}"}into the MCP entry so the forward survives--apply(inert on non-Claude hosts).Also fixes a latent bug the redesign exposed:
handle_for_keyhashed the sanitized (32-char-truncated) key while homes use the raw key hash → a 36-char session-id uuid resolved to the wrong home.Verification
cargo fmt --check+clippy -D warningsclean.WIRE_HOMEpin suppressed; healthy silent; cached walk still resolves the live session.pscaching, fleet-share false-positive, undocumented field, weak regression test).Existing frozen MCPs heal on the next
/mcp reconnect; the self-report makes that one-command recovery visible.🤖 Generated with Claude Code